package com.bci.internal.engine.bcibpmengine.service.impl;


import com.bci.internal.engine.bcibpmengine.instances.entity.ActHiActinst;
import com.bci.internal.engine.bcibpmengine.instances.mapper.ActHiActinstMapper;
import com.bci.internal.engine.bcibpmengine.service.ActivitiHistoryService;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.apache.commons.lang3.builder.DiffResult;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author jzwu
 * @since 2021/4/5 0005
 */
@Slf4j
@Service
public class ActivitiHistoryServiceImpl implements ActivitiHistoryService {

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private HistoryService historyService;

    @Resource
    private ActHiActinstMapper actHiActinstMapper;


    @Override
    public Map<String, Object> gethighLine(String instanceId, String assignee) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(instanceId).singleResult();
        Assert.notNull(historicProcessInstance, "没有该历史流程实例文件！");
        /* 获取bpmnModel对象 */
        BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
        /* 因为我们这里只定义了一个Process 所以获取集合中的第一个即可 */
        Process process = bpmnModel.getProcesses().get(0);
        /* 获取所有的FlowElement信息 */
        Collection<FlowElement> flowElements = process.getFlowElements();
        Map<String, String> map = new HashMap<>();
        for (FlowElement flowElement : flowElements) {
            //判断是否是连线
            if (flowElement instanceof SequenceFlow) {
                SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
                String ref = sequenceFlow.getSourceRef();
                String targetRef = sequenceFlow.getTargetRef();
                map.put(ref + targetRef, sequenceFlow.getId());
            }
        }
        //获取流程实例 历史节点(全部)
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .list();
        //各个历史节点   两两组合 key
        Set<String> keyList = new HashSet<>();
        for (HistoricActivityInstance i : list) {
            for (HistoricActivityInstance j : list) {
                if (i != j) {
                    keyList.add(i.getActivityId() + j.getActivityId());
                }
            }
        }
        //高亮连线ID
        Set<String> highLine = new HashSet<>();
        keyList.forEach(s -> highLine.add(map.get(s)));

        //获取流程实例 历史节点（已完成）
        List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .finished()
                .list();
        // 展示流程节点处理人
        HashMap<String, Object> nodeAssigneeMap = new HashMap<>(16);
        //高亮节点ID
        Set<String> highPoint = new HashSet<>();
        listFinished.forEach(s -> highPoint.add(s.getActivityId()));
        // 展示流程节点处理人
        List<String> listTaskIds = listFinished.stream()
                .filter(finishedNode -> finishedNode.getActivityId().contains("Activity"))
                .map(HistoricActivityInstance::getTaskId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(listTaskIds)) {
            /* 调用mapper的接口查询数据库后经过分组在组装为Map集合  */
            actHiActinstMapper.listByTaskAssignee(listTaskIds).stream().collect(Collectors.groupingBy(ActHiActinst::getActId))
                    .forEach((k, v) -> {
                        List<String> listNodeAssignee = new ArrayList<>();
                        v.forEach(historicActivityInstance -> listNodeAssignee.add(historicActivityInstance.getAssignee()));
                        nodeAssigneeMap.put(k, listNodeAssignee);
                    });
        }
        //获取流程实例 历史节点（待办节点）
        List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .unfinished()
                .list();
        //需要移除的高亮连线
        Set<String> set = new HashSet<>();
        //待办高亮节点
        Set<String> waitingToDo = new HashSet<>();
        listUnFinished.forEach(s -> {
            waitingToDo.add(s.getActivityId());

            for (FlowElement flowElement : flowElements) {
                //判断是否是 用户节点
                if (flowElement instanceof UserTask) {
                    UserTask userTask = (UserTask) flowElement;

                    if (userTask.getId().equals(s.getActivityId())) {
                        List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
                        //因为 高亮连线查询的是所有节点  两两组合 把待办 之后  往外发出的连线 也包含进去了  所以要把高亮待办节点 之后 即出的连线去掉
                        if (outgoingFlows != null && outgoingFlows.size() > 0) {
                            outgoingFlows.forEach(a -> {
                                if (a.getSourceRef().equals(s.getActivityId())) {
                                    set.add(a.getId());
                                }
                            });
                        }
                    }
                }
            }
        });
        highLine.removeAll(set);

        //获取当前用户
        Set<String> iDo = new HashSet<>(); //存放 高亮 我的办理节点
        //当前用户已完成的任务

        List<HistoricTaskInstance> taskInstanceList = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(assignee)
                .finished()
                .processInstanceId(instanceId).list();

        taskInstanceList.forEach(a -> iDo.add(a.getTaskDefinitionKey()));
        Map<String, Object> reMap = new HashMap<>();
        reMap.put("highPoint", highPoint);
        reMap.put("highLine", highLine);
        reMap.put("waitingToDo", waitingToDo);
        reMap.put("iDo", iDo);
        reMap.put("nodeAssignee", nodeAssigneeMap);
        return reMap;
    }
}